package cn.tangsihai.hrm.service.impl;

import cn.tangsihai.hrm.client.AuthClient;
import cn.tangsihai.hrm.constant.Constants;
import cn.tangsihai.hrm.domain.Login;
import cn.tangsihai.hrm.domain.VipBase;
import cn.tangsihai.hrm.domain.VipUser;
import cn.tangsihai.hrm.dto.RegisterPhoneDto;
import cn.tangsihai.hrm.mapper.VipBaseMapper;
import cn.tangsihai.hrm.mapper.VipUserMapper;
import cn.tangsihai.hrm.mark.MarkCode;
import cn.tangsihai.hrm.service.IVipUserService;
import cn.tangsihai.hrm.to.SendSMSCode;
import cn.tangsihai.hrm.util.AjaxResult;
import cn.tangsihai.hrm.util.AssertUtil;
import cn.tangsihai.hrm.util.BitStatesUtils;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;

/**
 * <p>
 * 会员登录账号 服务实现类
 * </p>
 *
 * @author sihai.tang
 * @since 2021-12-02
 */
@Service
public class VipUserServiceImpl extends ServiceImpl<VipUserMapper, VipUser> implements IVipUserService {
    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;
    @Autowired
    private AuthClient authClient;
    @Autowired
    private VipBaseMapper baseMapper;
    @Autowired
    private VipUserMapper userMapper;

    /**
     * 手机验证码注册
     *      1.参数合理性判断：JSR303
     *      2.手机号是否被注册
     *      3.校验验证码
     *      4.保存Login表---调用feign接口 注：集成feign
     *      5.保存user表
     *      6.保存base表
     *      7.删除Redis中的手机号验证码
     * @param dto
     */
    @Override
    @GlobalTransactional // 开启全局事务
    public void register(RegisterPhoneDto dto) {
        // 1.参数合理性判断：JSR303
        // 2.手机号是否被注册
        VipUser userFromDB = userMapper.selectByPhone(dto.getMobile());
        AssertUtil.isNull(userFromDB, "该手机号已被注册，请直接登录");

        // 3.校验验证码
        String key = String.format(MarkCode.REGISTER_PHONE_REDIS_KEY, dto.getMobile());
        SendSMSCode sendSMSCode = (SendSMSCode) redisTemplate.opsForValue().get(key);
        AssertUtil.isNotNull(sendSMSCode, "验证码已过期");
        AssertUtil.isEqualsIgnoreCase(dto.getSmsCode(), sendSMSCode.getSmsCode(), "验证码错误");

        // 4.保存Login表---调用feign接口 注：集成feign
        Login login = initLogin(dto);
        AjaxResult ajaxResult = authClient.saveLogin(login);
        AssertUtil.isNotNull(ajaxResult.getResultObj(), "保存Login失败");
        Long loginId = Long.valueOf(ajaxResult.getResultObj().toString());

        // 5.保存user表
        VipUser user = initUser(dto, loginId);
        super.insert(user);

        // 6.保存base表
        VipBase base = initBase(dto, user.getId());
        baseMapper.insert(base);

        // 7.删除Redis中的手机号验证码
        redisTemplate.delete(key);
    }

    // 准备user表数据
    private VipBase initBase(RegisterPhoneDto dto, Long id) {
        VipBase base = new VipBase();
        Date date = new Date();
        base.setCreateTime(date.getTime());
        base.setSsoId(id);
        base.setRegChannel(Integer.valueOf(dto.getRegChannel()));
        base.setRegTime(date.getTime());
        base.setGrowScore(0);
        return base;
    }

    // 准备user表数据
    private VipUser initUser(RegisterPhoneDto dto, Long loginId) {
        VipUser user = new VipUser();
        user.setCreateTime(new Date().getTime());
        user.setThirdUid(Constants.User.MOBILE_PHONE_NUMBER_LOGIN);
        user.setPhone(dto.getMobile());
        // TODO 密码要加密
        user.setPassword(dto.getPassword());

        // 位状态
        long bitState = BitStatesUtils.addState(0, BitStatesUtils.OP_ACTIVED);
        bitState = BitStatesUtils.addState(bitState, BitStatesUtils.OP_AUTHED_PHONE);
        user.setBitState(bitState);
        user.setLoginId(loginId);
        return user;
    }

    // 准备login表数据
    private Login initLogin(RegisterPhoneDto dto) {
        Login login = new Login();
        login.setUsername(dto.getMobile());
        //TODO 要加密
        login.setPassword(dto.getPassword());
        login.setType(Constants.Login.TYPE_RECEPTION);
        return login;
    }
}
